/*
 * NonBlockingMessageQueue.h
 *
 */

#ifndef NONBLOCKINGMESSAGEQUEUE_H_
#define NONBLOCKINGMESSAGEQUEUE_H_

#include "MessageQueue2.h"
#include "SharedMemory2.h"
#include "Semaphore.h"

//TODO hacer que la mem compartida separe por tipo de msj!!

template<class T>
class NonBlockingMessageQueue {
public:

	NonBlockingMessageQueue(std::string, int nTypes=256);

	virtual ~NonBlockingMessageQueue();

	void cleanup();

	void destroy();

	void put(MessageId_t id,T &data);

	T get(MessageId_t id);

	bool isEmpty(MessageId_t id);

private:
	MessageQueue2<T> m_queue;
	SharedMemory2<int> m_itemAmmount;
	Semaphore m_mutex;
	int m_nTypes;
};

template<class T>
NonBlockingMessageQueue<T>::NonBlockingMessageQueue(std::string archivo, int nTypes)
	:m_queue(archivo),
	m_itemAmmount(archivo,nTypes),
	m_mutex(archivo,'a',1),
	m_nTypes(nTypes)
{
}

template<class T>
NonBlockingMessageQueue<T>::~NonBlockingMessageQueue()
{

}

//TODO mejorar la interfaz de inicializacion
template<class T>
void NonBlockingMessageQueue<T>::cleanup()
{
	m_queue.destroy();

	int i;

	for(i=0;i <m_nTypes; i++)
		m_itemAmmount.write(0,i);
	m_mutex.init();
}

template<class T>
void NonBlockingMessageQueue<T>::destroy()
{
	m_mutex.destroy();
	m_queue.destroy();
}

template<class T>
void NonBlockingMessageQueue<T>::put(MessageId_t tipo,T &data)
{
	int count;
	m_queue.put(tipo, data);

	m_mutex.dec();
	count = m_itemAmmount.read(tipo);
	m_itemAmmount.write(count+1,tipo);
	m_mutex.inc();
}

template<class T>
T NonBlockingMessageQueue<T>::get(MessageId_t tipo)
{
	int count;
	T retVal = m_queue.get(tipo);

	m_mutex.dec();
	count = m_itemAmmount.read(tipo);
	m_itemAmmount.write(count-1,tipo);
	m_mutex.inc();

	return retVal;
}

template<class T>
bool NonBlockingMessageQueue<T>::isEmpty(MessageId_t tipo)
{
	int count;
	m_mutex.dec();
	count = m_itemAmmount.read(tipo);
	m_mutex.inc();

	return count == 0;
}

#endif /* NONBLOCKINGMESSAGEQUEUE_H_ */
